#include "DirtyFilterMgr.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include <iconv.h>
#include <string.h>
#include <regex>

const std::string DIRTY_FILES = "simple/dirty_en.txt;simple/dirty_and_usa.txt;simple/dirty_korea.txt;simple/dirty4.txt;simple/dirty5.txt;";


static bool isValidUTF8(const std::string& sStr) {
    int n = 0,j = 0;
    size_t ix = sStr.size();
    for (size_t i = 0; i < sStr.size(); ++ i) {
        char c = (unsigned char)sStr[i];
        if (0x00 <= c && c <= 0x7f) n=0; // 0bbbbbbb
        else if ((c & 0xE0) == 0xC0) n=1; // 110bbbbb
        else if ( c==0xed && i<(ix-1) && ((unsigned char)sStr[i+1] & 0xa0)==0xa0) {
            return false; //U+d800 to U+dfff
        }
        else if ((c & 0xF0) == 0xE0) n=2; // 1110bbbb
        else if ((c & 0xF8) == 0xF0) n=3; // 11110bbb
        else if ((c & 0xFC) == 0xF8) n=4; // 111110bb //byte 5, unnecessary in 4 byte UTF-8
        else if ((c & 0xFE) == 0xFC) n=5; // 1111110b //byte 6, unnecessary in 4 byte UTF-8
        else {
            printf("unknown %c %x \n", c, c);
          return false;
        }

        for (j=0; j<n && i<ix; j++) { // n bytes matching 10bbbbbb follow ?
            if ((++i == ix) || (( (unsigned char)sStr[i] & 0xC0) != 0x80)) {
                perror("-------------------");
                return false;
            }
        }
    }

    return true;
}

static bool utf82Unicode(const std::string& sStr, std::vector<uint32_t>& vResult) {

    const char* pStart = sStr.c_str();
    const char* pEnd = sStr.c_str() + sStr.size();
    uint32_t iValue = 0;
    char* pOutput = (char*)(&iValue);
    while (pStart != pEnd) {
        if (*pStart > 0x00 && *pStart <= 0x7F) //处理单字节UTF8字符（英文字母、数字）
        {
            *pOutput = *pStart;
            pOutput++;
            *pOutput = 0; //小端法表示，在高地址填补0
        }
        else if (((*pStart) & 0xE0) == 0xC0) //处理双字节UTF8字符
        {
            char high = *pStart;
            if (++pStart == pEnd) return false;

            char low = *pStart;
            if ((low & 0xC0) != 0x80)  //检查是否为合法的UTF8字符表示
            {
                return false; //如果不是则报错
            }

            *pOutput = (high << 6) + (low & 0x3F);
            pOutput++;
            *pOutput = (high >> 2) & 0x07;
        }
        else if (((*pStart) & 0xF0) == 0xE0) //处理三字节UTF8字符
        {
            char high = *pStart;
            //pStart++;
            if (++pStart == pEnd) return false;
            char middle = *pStart;
            //pStart++;
            if (++pStart == pEnd) return false;
            char low = *pStart;
            if (((middle & 0xC0) != 0x80) || ((low & 0xC0) != 0x80))
            {
                return false;
            }
            *pOutput = (middle << 6) + (low & 0x3F);//取出middle的低两位与low的低6位，组合成unicode字符的低8位
            pOutput++;
            *pOutput = (high << 4) + ((middle >> 2) & 0x0F); //取出high的低四位与middle的中间四位，组合成unicode字符的高8位
        }
        else if (((*pStart) & 0xF8) == 0xF0) { // 11110bbb
            char b1 = 0, b2 = 0, b3 = 0, b4 = 0;
            b1 = *pStart;
            if (++pStart == pEnd) return false;
            b2 = *pStart;
            if (++pStart == pEnd) return false;
            b3 = *pStart;
            if (++pStart == pEnd) return false;
            b4 = *pStart;

            if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
                    || ((b4 & 0xC0) != 0x80) )
                return false;
            *pOutput     = (b3 << 6) + (b4 & 0x3F);
            *(pOutput+1) = (b2 << 4) + ((b3 >> 2) & 0x0F);
            *(pOutput+2) = ((b1 << 2) & 0x1C)  + ((b2 >> 4) & 0x03);
        } else if (((*pStart) & 0xFC) == 0xF8) { // 111110bb //byte 5, unnecessary in 4 byte UTF-8
            char b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0;
            b1 = *pStart;
            if (++pStart == pEnd) return false;
            b2 = *pStart;
            if (++pStart == pEnd) return false;
            b3 = *pStart;
            if (++pStart == pEnd) return false;
            b4 = *pStart;
            if (++pStart == pEnd) return false;
            b5 = *pStart;
            if (((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
                        || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80) )
                return false;

            *pOutput     = (b4 << 6) + (b5 & 0x3F);
            *(pOutput+1) = (b3 << 4) + ((b4 >> 2) & 0x0F);
            *(pOutput+2) = (b2 << 2) + ((b3 >> 4) & 0x03);
            *(pOutput+3) = (b1 << 6);
        } else if (((*pStart) & 0xFE) == 0xFC) { // 1111110b //byte 6, unnecessary in 4 byte UTF-8
            char b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0;
            b1 = *pStart;
            if (++pStart == pEnd) return false;
            b2 = *pStart;
            if (++pStart == pEnd) return false;
            b3 = *pStart;
            if (++pStart == pEnd) return false;
            b4 = *pStart;
            if (++pStart == pEnd) return false;
            b5 = *pStart;
            if (++pStart == pEnd) return false;
            b6 = *pStart;

            if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
                        || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80)
                        || ((b6 & 0xC0) != 0x80) )
                return false;

            *pOutput     = (b5 << 6) + (b6 & 0x3F);
            *(pOutput+1) = (b5 << 4) + ((b6 >> 2) & 0x0F);
            *(pOutput+2) = (b3 << 2) + ((b4 >> 4) & 0x03);
            *(pOutput+3) = ((b1 << 6) & 0x40) + (b2 & 0x3F);
        } else { //对于其他字节数的UTF8字符不进行处理
            return false;
        }

        vResult.emplace_back(iValue);
        ++pStart;//处理下一个utf8字符
        iValue = 0;
        pOutput = (char*)(&iValue);
    }

    return true;
}

static void unicode2UTF8(std::vector<uint32_t>& vResult, std::string& sStr) {
    for (const auto& iValue : vResult) {
        if (iValue <= 0x7F) {
            sStr.push_back(iValue);
        } else if (iValue >= 0x80 && iValue <= 0x07FF) {
            sStr.push_back(((iValue >> 6)&0x1F) | 0xc0);
            sStr.push_back((iValue & 0x3f ) | 0x80);
        } else if (iValue >= 0x0800 && iValue <= 0xFFFF) {
            sStr.push_back(((iValue >> 12) & 0x0f) | 0xe0);
            sStr.push_back(((iValue >> 6) & 0x3f) | 0x80);
            sStr.push_back((iValue & 0x3f) | 0x80);
        } else if (iValue >= 0x10000 && iValue <= 0x1FFFFF) {
            sStr.push_back(((iValue >> 18) & 0x07) | 0xf0);
            sStr.push_back(((iValue >> 12) & 0x3f) | 0x80);
            sStr.push_back(((iValue >> 6) & 0x3f) | 0x80);
            sStr.push_back((iValue & 0x3f) | 0x80);
        } else if (iValue >= 0x200000 && iValue <= 0x3FFFFFF) {
            sStr.push_back(((iValue >> 24) & 0x03) | 0xf8);
            sStr.push_back(((iValue >> 18) & 0x3f) | 0x80);
            sStr.push_back(((iValue >> 12) & 0x3f) | 0x80);
            sStr.push_back(((iValue >> 6) & 0x3f) | 0x80);
            sStr.push_back((iValue & 0x3f) | 0x80);
        } else if (iValue >= 0x4000000 && iValue <= 0x7FFFFFFF) {
            sStr.push_back(((iValue >> 30) & 0x01) | 0xfc);
            sStr.push_back(((iValue >> 24) & 0x3f) | 0x80);
            sStr.push_back(((iValue >> 18) & 0x3f) | 0x80);
            sStr.push_back(((iValue >> 12) & 0x3f) | 0x80);
            sStr.push_back(((iValue >> 6) & 0x3f) | 0x80);
            sStr.push_back((iValue & 0x3f) | 0x80);
        } else {
            perror("no deal case");
            exit(-1);
        }
    }
}

void DirtyFilterMgr::init() {
    //std::ifstream ifs;
    //ifs.open("simple/dirty4.txt", std::ios::in);
    //if (!ifs.is_open()) {
        //std::cout << "文件打开失败" << std::endl;
        //exit(-1);
    //}
    std::regex reg(";");
    std::vector<std::string> vFiles(std::sregex_token_iterator(DIRTY_FILES.begin(), DIRTY_FILES.end(), reg, -1), std::sregex_token_iterator());
    std::vector<std::string> elems(std::sregex_token_iterator(DIRTY_FILES.begin(), DIRTY_FILES.end(), reg, -1), std::sregex_token_iterator());

    for (const auto& sFile : vFiles) {
        std::cout << "------------------addWord-------------------" << sFile << std::endl;
        std::ifstream ifs2(sFile);
        std::string sContent ((std::istreambuf_iterator<char>(ifs2)), std::istreambuf_iterator<char>());
        if (!isValidUTF8(sContent)) {
            std::cout << "invalid utf8 format" << std::endl;
            exit(-1);
        }
        std::string sLine;
        std::stringstream ss(sContent);
        while (getline(ss, sLine)) {
            //if (!isValidUTF8(sLine)) {
            //std::cout << "invalid utf8 format:" << sLine << std::endl;
            //exit(-1);
            //}
            std::vector<uint32_t> vUniocodes;
            if (!utf82Unicode(sLine, vUniocodes)) {
                perror("utf82Unicode error");
                exit(-1);
            }

            m_stDirtyWords.addNode(vUniocodes);
        }
    }
}

int32_t DirtyFilterMgr::replaceDirtyWord(const std::string& sSrc, std::string& sTo) {
    if (!isValidUTF8(sSrc)) {
        perror("unvalid utf8");
        return -1;
    }
    std::vector<uint32_t> vUniocodes;
    if (!utf82Unicode(sSrc, vUniocodes) || vUniocodes.empty()) {
        perror("utf82Unicode error");
        return -1;
    }
    uint32_t* pStart = &vUniocodes[0];
    uint32_t* pEnd = pStart + vUniocodes.size();
    uint32_t iLen = 0;
    bool bReplaced = false;
    for (uint32_t* pIdx = pStart; pIdx < pEnd;) {
        if (!m_stDirtyWords.find(pIdx, pEnd, iLen)) {
            ++pIdx;
            continue;
        }

        for (uint32_t i = 0; i < iLen; ++i) {
            *(pIdx+i) = 42; // 赋值为 符号'*'
            bReplaced = true;
        }
        pIdx += iLen;
        iLen = 0;
    }


    if (bReplaced)
        unicode2UTF8(vUniocodes, sTo);
    else
        sTo = sSrc;

    return 0;
}

void DirtyFilterMgr::addWord(const std::string& sStr) {
    if (!isValidUTF8(sStr)) {
        std::cout << "invalid utf8 format:" << sStr << std::endl;
        exit(-1);
    }
    std::vector<uint32_t> vUniocodes;
    if (!utf82Unicode(sStr, vUniocodes) || vUniocodes.empty()) {
        perror("utf82Unicode error");
        exit(-1);
    }
    std::cout << "------------------addWord-------------------" << std::endl;
    for (const auto& iVal : vUniocodes) {
        std::cout << iVal << ", ";
    }
    std::cout << std::endl;

    m_stDirtyWords.addNode(vUniocodes);
}

int main(int argc, const char **argv) {
    DirtyFilterMgr mgr;
    mgr.init();
    //std::string sTmp = "我是你大爷abc123";
    std::string sTmp = "我日卵子妈了个巴子杀人放火";
    std::string sTmp2;
    if (mgr.replaceDirtyWord(sTmp, sTmp2) != 0) {
        perror("replace error");
        exit(-1);
    }
    std::cout << sTmp << std::endl;
    std::cout << sTmp2 << std::endl;

    return 0;
}
